package Sorting;

import DataStructuresThreads.ListThread;
import DataStructuresThreads.QueueThread;
import DataStructuresThreads.StackThread;
import DataStructuresThreads.VectorThread;
import SortingThreads.*;
import com.sun.j3d.utils.behaviors.vp.OrbitBehavior;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.universe.SimpleUniverse;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.j3d.*;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;

/**
 *
 * @author rafael
 */
public class Main {

    public static float raio = 0.1f;
    public static float distancia = 0.0f; //Espaçamento entre os objetos.
    public static SimpleUniverse su;
    public static int size, capacity;
    public TextureLoader carregador;
    public static int movementSleep = 30;
    public static Texto[] vetorFrases = new Texto[10];
    public static Texto[] vetorValores = new Texto[6];
    public static double posicaoXBox = -1.7;
    public static double posicaoYBox = 0.75;
    public static double boxPosition = 0.1;
    public static float TAM = 0.1f;
    private static TransformGroup tgCursor;
    private static TransformGroup tgText;
    private static BranchGroup bgText;
    private static int selectionNumber;
    private static Vector3f tempPosition;
    private static Vector3f shellPositions = new Vector3f(-0.3f, 0.0f, 0.0f);
    public static Number[] vetorNumeros, vetorCounting;
    public static final String[] opcoes = {"Bubble Sort", "Insertion Sort", "Selection Sort"};
    public static final String[] fimDaExecucao = {"Começar de novo", "Sair do Programa"};
    public static int sortingNumber;
    public static SimpleAttributeSet defaultText = new SimpleAttributeSet();
    public static SimpleAttributeSet highlightedText = new SimpleAttributeSet();
    public static JTextPane textPane, textPane2;
    public static JPanel buttonPanel;
    public static boolean isRunning = false;
    public static String textoBubble = "       BUBBLE SORT     \n\n\n\n"
            + "para ( i = tamanho_vetor; i >= 1; i-- ) { \n\n"
            + "   para ( j = 1; j < i; j++ ) {\n\n"
            + "      se ( v[ j - 1 ].valor( ) > v [ j ].valor( ) ) {\n"
            + "      auxiliar = v[ j ];\n"
            + "      v[ j ] = v[ j - 1 ];\n"
            + "      v[ j - 1 ] = auxiliar;\n\n"
            + "      }\n\n"
            + "   }\n\n"
            + "}";
    public static String textoInsertion = "       INSERTION SORT     \n\n\n"
            + "para(i = 1; i < tamanho_vetor; i++){\n\n"
            + "   j = i;\n\n"
            + "      enquanto(v[ j ] < v[ j - 1 ]) {\n\n"
            + "         auxiliar = v[ j ];\n"
            + "         v[ j ] = v[ j - 1 ];\n"
            + "         v[ j - 1 ] = auxiliar;\n"
            + "         j--.\n\n"
            + "         se(j == 0) quebrar o laço;\n\n"
            + "      }\n"
            + "}\n";
    public static String textoSelection = "            \tSELECTION SORT \n\n\n"
            + "para ( int i = 0; i < tamanho_vetor; i++ ) {\n\n"
            + "  index_min = i\n\n"
            + "    para ( int j = i + 1; j < tamanho_vetor; j++ ) {\n\n"
            + "      se ( v [ j ] < v [ index_min ] ) {\n"
            + "      index_min = j;\n"
            + "      }\n\n"
            + "    }\n\n"
            + "    se ( index_min != i ) {\n\n"
            + "      aux = v [ index_min ];\n"
            + "      v [ index_min ] = v [ i ];\n"
            + "      v [ i ] = aux;\n\n"
            + "    }\n\n"
            + "}";
    public static String textoQuick = "        IN-PLACE QUICKSORT \t\t\n\n"
            + "se ( comeco >= fim ) {\n"
            + "  retorne;\n"
            + "}\n\n"
            + "pivo = v [ fim ];\n"
            + "l = comeco;\n"
            + "r = fim - 1;\n\n"
            + "enquanto( l <= r) {\n"
            + "  enquanto ( l <= r e v [ l ] <= pivo ) {\n"
            + "     l++;\n"
            + "  }\n"
            + "  enquanto ( r >= l e v [ r ] >= pivo ) {\n"
            + "     r--;\n"
            + "  }\n"
            + "  se ( l < r ) {\n"
            + "    auxiliar = v [ l ];\n"
            + "    v [ l ] = v [ r ];\n"
            + "    v [ r ] = auxiliar;\n"
            + "  }\n"
            + "}\n\n"
            + "  auxiliar = v [ l ];\n"
            + "  v [ l ] = v [ fim ];\n"
            + "  v [ fim ] = auxiliar;\n"
            + "  inPlaceQuickSort(v, comeco, l - 1);\n"
            + "  inPlaceQuickSort(v, l + 1, fim);";
    public static final String textoCounting = "        COUNTING SORT \t\t\n\n"
            + "para (int i = 0; i < vetor.tamanho; i++) {\n\n"
            + " vetorContagem[ vetorContagem[ i ] - minimo]++;\n\n"
            + "}\n\n"
            + "z = 0;\n\n"
            + "para (int i = minimo; i <= maximo; i++) {\n\n"
            + "  enquanto (vetorContagem[i - minimo] > 0) {\n\n"
            + "    vetor[ z ] = i;\n"
            + "    z++;\n"
            + "    vetorContagem[i - min]--;\n\n"
            + "  }\n\n"
            + "}\n\n";
    public static final String textoShell = "        SHELL SORT \t\t\n\n"
            + "h = 1;\n\n"
            + "faça { \n\n"
            + "  h = h * 3 + 1;\n\n"
            + "} enquanto( h < vetor_tamanho) ;\n\n"
            + "faça {\n\n"
            + "  h = h/3;\n\n"
            + "    para i de h até vetor_tamanho {\n\n"
            + "      x = v[ i ];\n"
            + "      j = i;\n\n"
            + "        enquanto ( v[ j - h] > x) {\n\n"
            + "          v[ j ] = v [ j - h ];\n"
            + "          j = j - h;\n"
            + "          se ( j < h ) pare;\n\n"
            + "        };\n\n"
            + "      v [ j ] = x;\n\n"
            + "} enquanto ( h != 1);";
    public static final String textoMerge = "        MERGE SORT \t\t\n\n"
            + "se (tamanho_vetor < 2) retorne; \n\n"
            + "i = 0, j = 0, k = 0;\n"
            + "n1 = tamanho_vetor / 2;\n"
            + "n2 = (tamnho_vetor % 2 == 0) ? (tamanho_vetor / 2) : (tamanho_vetor / 2 + 1);\n\n"
            + "v1 = vetor[n1];\n"
            + "v2 = vetor[n2];\n\n"
            + "faça {\n"
            + "v1 [ i++ ] = v [ k++ ];\n"
            + "} enquanto ( k < ( tamanho_vetor / 2 );\n\n"
            + "faca {\n"
            + "v2 [ j++ ] = v [ k++ ];\n"
            + "} enquanto ( k < tamanho_vetor );\n\n"
            + "mergeSort(v1, n1);\n"
            + "mergeSort(v2, n2);\n"
            + "merge(v1, n1, v2, n2, v);\n\n\n"
            + "           MERGE(v1, n1, v2, n2, v)\n\n"
            + "i = 0, j = 0, k = 0;\n\n"
            + "enquanto ( i < n1 && j < n2 ) { \n\n"
            + "  se (v1 [ i ] < v2 [ j ]{\n"
            + "    v [ k++ ] = v1 [ i++ ];\n"
            + "  } senao {\n"
            + "    v [ k++ ] = v2 [ j++ ];\n"
            + "  }\n\n"
            + "}\n\n"
            + "enquanto ( i < n1 ) {\n"
            + "  v [ k++ ] = v1 [ i++ ];\n"
            + "};\n\n"
            + "enquanto ( j < n2 ) {\n"
            + "  v [ k++ ] = v2 [ j++ ];\n"
            + "};\n\n";
    public static final String algoritmo = "Algoritmo de ordenação à ser definido.";
    public static final String algoritmo2 = "Local de variáveis de ordenação.";
    public static int start, end, trace;
    public static String descricaoBubble = "\t\tBUBBLE SORT \n\n\n"
            + "O bubble sort, ou ordenação por flutuação (literalmente 'por bolha'), é "
            + "um algoritmo de ordenação dos mais simples. A ideia é percorrer o vector "
            + "diversas vezes, a cada passagem fazendo flutuar para o topo o maior "
            + "elemento da sequência. Essa movimentação lembra a forma como as bolhas "
            + "em um tanque de água procuram seu próprio nível, e disso vem o nome do algoritmo. "
            + "No melhor caso, o algoritmo executa operações relevantes, onde n representa "
            + "o número de elementos do vector. No pior caso, são feitas operações. A "
            + "complexidade desse algoritmo é de Ordem quadrática. Por isso, ele não é "
            + "recomendado para programas que precisem de velocidade e operem com "
            + "quantidade elevada de dados.";
    public static String descricaoSelection = "\t\tSELECTION SORT \n\n"
            + "Selection sort is one of the O(n2) sorting algorithms, which makes it quite\n "
            + "inefficient for sorting large data volumes. Selection sort is notable for its \n "
            + "programming simplicity and it can over perform other sorts in certain \n "
            + "situations (see complexity analysis for more details)\n\n."
            + "The idea of algorithm is quite simple. Array is imaginary divided into two parts\n"
            + "- sorted one and unsorted one. At the beginning, sorted part is empty, while \n"
            + "unsorted one contains whole array. At every step, algorithm finds minimal\n"
            + "element in the unsorted part and adds it to the end of the sorted one. When\n"
            + "unsorted part becomes empty, algorithm stops.When algorithm sorts an array,\n"
            + "it swaps first element of unsorted part with minimal element and then it is\n"
            + "included to the sorted part. This implementation  of selection sort in not stable.\n"
            + "In case of linked list is sorted and instead of swaps, minimal element is linked\n"
            + "to the unsorted part, selection sort is stable.";
    public static String descricaoInsertion = "Descrição do Insertion";
    public static String descricaoQuick = "Descrição do Quick";
    public static JTextArea helpText;
    public static JPanel panel;
    public static JFrame frame;
    public static Number changeableVector[];
    public static Number firstSubVector[];
    public static Number fsvSubVector1[];
//    public static Number fsvsfSubVector1[];
//    public static Number fsvsfSubVector2[];
    public static Number fsvSubVector2[];
    public static Number fsvssSubVector1[];
    public static Number fsvssSubVector2[];
    //SECOND SUBVECTOR
    public static Number secondSubVector[];
    public static Number ssvSubVector1[];
    // os 2 pra acrescentar quando tiver 8 elementos
    public static Number ssvSubVector2[];
    public static Number ssvssSubVector1[];
    public static Number ssvssSubVector2[];
    public static int mergeCallStack = 0;
    public static Score sc = new Score();
    public static float coordinate_x = 0.0f;
    public static float coordinate_y = -0.3f;
    public static float aux_coordinate_x = 0.0f;
    public static float aux_coordinate_y = -0.3f;
    public static int stackCapacity, queueCapacity;
    public static int stackSize, queueSize;
    public static ArrayList<Number> numberList;
    public static int vectorSize, vectorCapacity;
//    public static
    public static ArrayList<Number> vectorShadowList;
    public static String textoStack = "        PILHA \t\t\n\n"
            + "push(int numero) {\n"
            + "  se (tamanho == capacidade) {\n"
            + "    Erro: Não há capacidade para mais elementos!\n"
            + "  } senao {\n"
            + "    pilha[tamanho] = numero;\n"
            + "    tamanho++;\n"
            + "  }\n"
            + "}\n\n"
            + "pop() {\n"
            + "  se(tamanho == 0) {\n"
            + "    Erro: Não há elementos à serem retirados!\n"
            + "  } senao  {\n"
            + "    pilha[tamanho - 1] = null;\n"
            + "    tamanho--;\n"
            + "  }\n"
            + "}\n\n"
            + "top() {\n"
            + "  se (tamanho == 0) {\n"
            + "    Erro: Não há elementos na pilha!\n"
            + "  } senao   {\n"
            + "    int top = pilha[tamanho - 1];\n"
            + "  }\n"
            + "  retorna top;\n"
            + "}";
    public static String textoQueue = "        FILA \t\t\n\n"
            + "Inserir Elemento(int numero) {\n"
            + "  se (tamanho == capacidade) {\n"
            + "    Erro: Não há capacidade para mais elementos!\n"
            + "  } senao {\n"
            + "    fila[tamanho] = numero;\n"
            + "    tamanho++;\n"
            + "  }\n"
            + "}\n\n"
            + "Remover Elemento() {\n"
            + "  se(tamanho == 0) {\n"
            + "    Erro: Não há elementos à serem retirados!\n"
            + "  } senao  {\n"
            + "    fila[0] = null;\n"
            + "    tamanho--;\n"
            + "  }\n"
            + "}\n\n"
            + "Front() {\n"
            + "  se (tamanho == 0) {\n"
            + "    Erro: Não há elementos na fila!\n"
            + "  } senao   {\n"
            + "  retorna fila[0];\n"
            + "  }\n"
            + "}";
    public static String textoVectorAdd = "        VETOR \t\t\n\n"
            + "Inserir Elemento(int indice, int numero) {\n"
            + "  se (indice < 0 || indice > tamanho_vetor) {\n"
            + "    Erro: O índice não está nos limites do vetor!\n"
            + "  } senao {\n"
            + "    se (tamanho_vetor == capacidade_vetor) {\n"
            + "      vetorTemp = vetor[tamanho_vetor];\n"
            + "        para (int i = 0; i < tamanho_vetor; i++) {\n"
            + "          vetorTemp[i] = vetor[i];\n"
            + "        }\n"
            + "      vetor = novo vetor[vetor_capacidade * 2];\n"
            + "        para (int i = 0; i < vetor_capacidade / 2; i++) {\n"
            + "          vetor[i] = vetorTemp[i];\n"
            + "        }\n"
            + "    }\n"
            + "    para (int i = tamanho_vetor; i > indice; i--) {\n"
            + "      vetor[i] = vetor[i - 1];\n"
            + "    }\n"
            + "    vetor[indice] = numero;\n"
            + "    tamanho_vetor++;\n"
            + "  }";
    public static String textoVectorRemove = "        VETOR \t\t\n\n"
            + "Remover Elemento(int indice) {\n"
            + "  se (indice < 0 || indice >= tamanho_vetor) {\n"
            + "    Erro: O índice não está nos limites do vetor!\n"
            + "  } senao {\n"
            + "    vetor[indice] = null;\n"
            + "    para(int i = indice; i < tamanho_vetor; i++) {\n"
            + "      se (i != tamanho_vetor) {\n"
            + "        vetor[i] = vetor[i + 1];\n"
            + "      }\n"
            + "    }\n"
            + "    tamanho_vetor--;"
            + "  }\n"
            + "}";
    public static String textoListaAdd = "        LISTA \t\t\n\n"
            + "Inserir Elemento(int indice, int valor) {\n"
            + "  se (indice < 0 || indice > tamanho_lista) {\n"
            + "    Erro: Indice fora da lista!\n"
            + "  }\n"
            + "  se (head == tail) {\n"
            + "    head.setProximo(novo No(valor, head, tail));\n"
            + "    tail.setAnterior(head.proximo);\n"
            + "  } senao {\n"
            + "    No elemento = head;\n"
            + "    para (int i = 0; i < indice; i++) {\n"
            + "      elemento = elemento.getProximo();\n"
            + "    }\n"
            + "    No elemento2 = elemento.getProximo();\n"
            + "    elemento.setProximo(novo No(valor, elemento.getProximo(), elemento);\n"
            + "    elemento2.setAnterior(elemento.getProximo());\n"
            + "  }\n"
            + "  tamanho_lista++;\n"
            + "}";
    public static String textoListaRemove = "        LISTA \t\t\n\n"
            + "Remover Elemento(int indice) {\n"
            + "  No elemento = head;\n"
            + "  se (indice > 0 || indice > tamanho_vetor - 1) {\n"
            + "    Erro: Indice fora da lista!\n"
            + "  }\n"
            + "  se (indice == 0) {\n"
            + "    elemento = head.getProximo();\n"
            + "    head.getProximo().getProximo().setAnterior(head);\n"
            + "    head.setProximo(head.getProximo().getProximo());\n"
            + "  } senao {\n"
            + "    para (int i = 0; i < indice; i++) {\n"
            + "      elemento = elemento.getProximo();\n"
            + "    }\n"
            + "    elemento.getProximo().getProximo().setAnterior(elemento);\n"
            + "    elemento.setProximo(elemento.getProximo().getProximo());\n"
            + "  }\n"
            + "  tamanho_lista--;\n"
            + "}";

    public static void shellSortFinal(Number v[]) {

        System.out.print("{ ");
        for (Number n : v) {
            System.out.print(n.getNumber() + " ");
        }
        System.out.println("}");
        highlightsText("h = 1;\n\n", textoShell);
        int i, j, h = 1;
        Number value;
        textPane2.setText("h =" + h);


        highlightsText("faça { \n\n", textoShell);
        do {
            highlightsText("  h = h * 3 + 1;\n\n", textoShell);
            h = 3 * h + 1;
            textPane2.setText("h = " + h);
        } while (h < v.length);
        highlightsText("} enquanto( h < vetor_tamanho) ;\n\n", textoShell);


        highlightsText("faça {\n\n", textoShell);
        do {
            highlightsText("  h = h/3;\n\n", textoShell);
            h = h / 3;
            textPane2.setText("h = " + h);

            highlightsText("    para i de h até vetor_tamanho {\n\n", textoShell);
            for (i = h; i < v.length; i++) {
                textPane2.setText("h = " + h + "\n"
                        + "i = " + i + "\ntamanho_vetor = " + v.length);
                highlightsText("      x = v[ i ];\n", textoShell);
                value = v[i];
                textPane2.setText("h = " + h + "\n"
                        + "i = " + i + "\ntamanho_vetor = " + v.length
                        + "\nx = " + value.numero);

                highlightsText("      j = i;\n\n", textoShell);
                j = i;
                textPane2.setText("h = " + h + "\n"
                        + "i = " + i + "\n tamanho_vetor = " + v.length
                        + "\n x = " + value.numero + "\nj = " + j);

                highlightsText("        enquanto ( v[ j - h] > x) {\n\n", textoShell);

                while (v[j - h].getNumber() > value.getNumber()) {
                    nextSwap(v, j, v[j].getNumber(), j - h);
                    moverObjetoGeneric(v, j - h, j, "shell");
                    v[j] = v[j - h];
                    textPane2.setText("h = " + h + "\n"
                            + "i = " + i + "\n tamanho_vetor = " + v.length
                            + "\n x = " + value.numero + "\nj = " + j + "\nv[j] = " + v[j].numero);
                    j = j - h;
                    textPane2.setText("h = " + h + "\n"
                            + "i = " + i + "\n tamanho_vetor = " + v.length
                            + "\n x = " + value.numero + "\nj = " + j + "\nv[j] = " + v[j].numero);

                    highlightsText("          se ( j < h ) pare;\n\n", textoShell);
                    if (j < h) {
                        break;
                    }

                }


                highlightsText("      v [ j ] = x;\n\n", textoShell);
                v[j] = value;
                textPane2.setText("h = " + h + "\n"
                        + "i = " + i + "\n tamanho_vetor = " + v.length
                        + "\n x = " + value.numero + "\nj = " + j + "\nv[j] = " + v[j].numero);


            }
//            System.out.print("Vector: ");
//            System.out.print("{ ");
//            for (Number n : v) {
//                System.out.print(n.getNumber() + " ");
//            }
//            System.out.println("}");
//            JOptionPane.showMessageDialog(null, "Impressão!");

            highlightsText("} enquanto ( h != 1);", textoShell);
        } while (h != 1);

        System.out.print("{ ");
        for (Number n : v) {
            System.out.print(n.getNumber() + " ");
        }
        System.out.println("}");

    }

    public static void getMergePositionV1(Number v[], int elements) {
        if (selectionNumber == 6) {
            if (mergeCallStack == 3) {
                su.addBranchGraph(addCustomBranchGroup(v, elements, 0.25f, -0.9f));
            } else if (mergeCallStack == 4) {
                su.addBranchGraph(addCustomBranchGroup(v, elements, 0.85f, -0.6f));
            } else if (mergeCallStack == 5) {
                su.addBranchGraph(addCustomBranchGroup(v, elements, 1.1f, -0.9f));
            } else {
                su.addBranchGraph(addCustomBranchGroup(v, elements, coordinate_x, coordinate_y));
            }
        }
    }

    public static void getMergePositionV2(Number v[], int elements, int aux) {

        if (mergeCallStack == 6) {

            if (mergeCallStack == 3) {
                su.addBranchGraph(addCustomBranchGroup(v, elements, 0.25f + (aux * 0.3f), -0.9f));
            } else if (mergeCallStack == 4) {
                su.addBranchGraph(addCustomBranchGroup(v, elements, 0.85f + (aux * 0.3f), -0.6f));
            } else if (mergeCallStack == 5) {
                su.addBranchGraph(addCustomBranchGroup(v, elements, 1.1f + (aux * 0.3f), -0.9f));
            } else {
                su.addBranchGraph(addCustomBranchGroup(v, elements, (aux * 0.3f), coordinate_y));
            }
        }

    }

    public static void mergeSort(Number v[], int size) {

        highlightsText("se (tamanho_vetor < 2) retorne; \n\n", textoMerge);
        if (size < 2) {
            return;
        }

        mergeCallStack++;
        highlightsText("i = 0, j = 0, k = 0;\n", textoMerge);
        int i = 0, j = 0, k = 0;
        highlightsText("n1 = tamanho_vetor / 2;\n ", textoMerge);
        int n1 = size / 2;
        highlightsText("n2 = (tamnho_vetor % 2 == 0) ? (tamanho_vetor / 2) : (tamanho_vetor / 2 + 1);\n\n", textoMerge);
        int n2 = (size % 2 == 0) ? (size / 2) : (size / 2 + 1);

        highlightsText("v1 = vetor[n1];\n", textoMerge);

        //estratégia de criação v2 START
        if (mergeCallStack == 1) {
            firstSubVector = new Number[n1];
        } else if (mergeCallStack == 2) {
            fsvSubVector1 = new Number[n1];
        } else if (mergeCallStack == 3) {
            fsvssSubVector1 = new Number[n1];
        } else if (mergeCallStack == 4) {
            ssvSubVector1 = new Number[n1];
        } else if (mergeCallStack == 5) {
            ssvssSubVector1 = new Number[n1];
        }//AQUI TUDO PRA 6;
//        Number v1[] = new Number[n1]
        //estratégia de criação v2 END

        highlightsText("v2 = vetor[n2];\n\n", textoMerge);
        //estratégia de criação v2 START
        if (mergeCallStack == 1) {
            secondSubVector = new Number[n2];
        } else if (mergeCallStack == 2) {
            fsvSubVector2 = new Number[n2];
        } else if (mergeCallStack == 3) {
            fsvssSubVector2 = new Number[n2];
        } else if (mergeCallStack == 4) {
            ssvSubVector2 = new Number[n2];
        } else if (mergeCallStack == 5) {
            ssvssSubVector2 = new Number[n2];
        }
//        Number v2[] = new Number[n2];
        //estratégia de criação v2 END

        highlightsText("faça {\n", textoMerge);
        do {
            highlightsText("v1 [ i++ ] = v [ k++ ];\n", textoMerge);
//                v1[i++] = v[k++];

            if (mergeCallStack == 1) {
                firstSubVector[i++] = vetorNumeros[k++];
            } else if (mergeCallStack == 2) {
                fsvSubVector1[i++] = firstSubVector[k++];
            } else if (mergeCallStack == 3) {
                fsvssSubVector1[i++] = fsvSubVector2[k++];
            } else if (mergeCallStack == 4) {
                ssvSubVector1[i++] = secondSubVector[k++];
            } else if (mergeCallStack == 5) {
                ssvssSubVector1[i++] = ssvSubVector2[k++];
            }


        } while (k < (size / 2));

        /*
         * MUDAR AQUI O BRANCH
         */
        if (mergeCallStack == 1) {
            su.addBranchGraph(addCustomBranchGroup(firstSubVector, n1, coordinate_x, coordinate_y));
        } else if (mergeCallStack == 2) {
            su.addBranchGraph(addCustomBranchGroup(fsvSubVector1, n1, coordinate_x, coordinate_y));
        } else if (mergeCallStack == 3) {
            su.addBranchGraph(addCustomBranchGroup(fsvssSubVector1, n1, 0.25f, -0.9f));
        } else if (mergeCallStack == 4) {
            su.addBranchGraph(addCustomBranchGroup(ssvSubVector1, n1, 0.85f, -0.6f));
        } else if (mergeCallStack == 5) {
            su.addBranchGraph(addCustomBranchGroup(ssvssSubVector1, n1, 1.1f, -0.9f));
        }
        //getMergePositionV1(v1, n1);
            /*
         * FIM
         */

        highlightsText("faca {\n", textoMerge);
        do {
            highlightsText("v2 [ j++ ] = v [ k++ ];\n", textoMerge);


            if (mergeCallStack == 1) {
                secondSubVector[j++] = vetorNumeros[k++];
            } else if (mergeCallStack == 2) {
                fsvSubVector2[j++] = firstSubVector[k++];
            } else if (mergeCallStack == 3) {
                fsvssSubVector2[j++] = fsvSubVector2[k++];
            } else if (mergeCallStack == 4) {
                ssvSubVector2[j++] = secondSubVector[k++];
            } else if (mergeCallStack == 5) {
                ssvssSubVector2[j++] = ssvSubVector2[k++];
            }

//                v2[j++] = v[k++];
        } while (k < size);


        /*
         * MUDAR AQUI O BRANCH
         */
        if (mergeCallStack == 1) {
            su.addBranchGraph(addCustomBranchGroup(secondSubVector, n2, (n1 * 0.3f), coordinate_y));
        } else if (mergeCallStack == 2) {
            su.addBranchGraph(addCustomBranchGroup(fsvSubVector2, n2, (n1 * 0.3f), coordinate_y));
        } else if (mergeCallStack == 3) {
            su.addBranchGraph(addCustomBranchGroup(fsvssSubVector2, n2, 0.25f + (n1 * 0.3f), -0.9f));
        } else if (mergeCallStack == 4) {
            su.addBranchGraph(addCustomBranchGroup(ssvSubVector2, n2, 0.85f + (n1 * 0.3f), -0.6f));
        } else if (mergeCallStack == 5) {
            su.addBranchGraph(addCustomBranchGroup(ssvssSubVector2, n2, 1.1f + (n1 * 0.3f), -0.9f));
        }
//            getMergePositionV2(v2, n2, n1);
            /*
         * FIM
         */


        System.out.println("CallStack:" + mergeCallStack);

        coordinate_x -= 0.1f;
        coordinate_y -= 0.3f;


        System.out.println("x = " + coordinate_x);
        System.out.println("y = " + coordinate_y);


        highlightsText("mergeSort(v1, n1);\n", textoMerge);
        if (mergeCallStack == 1) {

            mergeSort(firstSubVector, n1);
            highlightsText("mergeSort(v2, n2);\n", textoMerge);
            mergeSort(secondSubVector, n2);
            highlightsText("merge(v1, n1, v2, n2, v);\n\n\n", textoMerge);
            merge(firstSubVector, n1, secondSubVector, n2, vetorNumeros);

        } else if (mergeCallStack == 2) {

            mergeSort(fsvSubVector1, n1);
            highlightsText("mergeSort(v2, n2);\n", textoMerge);
            mergeSort(fsvSubVector2, n2);
            highlightsText("merge(v1, n1, v2, n2, v);\n\n\n", textoMerge);
            merge(fsvSubVector1, n1, fsvSubVector2, n2, firstSubVector);

        } else if (mergeCallStack == 3) {

            mergeSort(fsvssSubVector1, n1);
            highlightsText("mergeSort(v2, n2);\n", textoMerge);
            mergeSort(fsvssSubVector2, n2);
            highlightsText("merge(v1, n1, v2, n2, v);\n\n\n", textoMerge);
            merge(fsvssSubVector1, n1, fsvssSubVector2, n2, fsvSubVector2);

        } else if (mergeCallStack == 4) {

            mergeSort(ssvSubVector1, n1);
            highlightsText("mergeSort(v2, n2);\n", textoMerge);
            mergeSort(ssvSubVector2, n2);
            highlightsText("merge(v1, n1, v2, n2, v);\n\n\n", textoMerge);
            merge(ssvSubVector1, n1, ssvSubVector2, n2, secondSubVector);

        } else if (mergeCallStack == 5) {

            mergeSort(ssvssSubVector1, n1);
            highlightsText("mergeSort(v2, n2);\n", textoMerge);
            mergeSort(ssvssSubVector2, n2);
            highlightsText("merge(v1, n1, v2, n2, v);\n\n\n", textoMerge);
            merge(ssvssSubVector1, n1, ssvssSubVector2, n2, ssvSubVector2);

        }


    }

    public static void merge(Number v1[], int n1, Number v2[], int n2, Number v[]) {


        int i = 0, j = 0, k = 0;

        while (i < n1 && j < n2) {

            if (v1[i].getNumber() <= v2[j].getNumber()) {
                v[k++] = v1[i++];
            } else {
                v[k++] = v2[j++];
            }
            System.out.println("CallStack = " + mergeCallStack);
            destroySphereMerge(v, k - 1);
            su.addBranchGraph(respawnSphereMerge(v, k - 1));
            sleep(2000);
        }

        while (i < n1) {
            v[k++] = v1[i++];
//            destroySphereMerge(v, k - 1);
//            su.addBranchGraph(respawnSphereMerge(v, k - 1));
//            sleep(2000);
        }

        while (j < n2) {
            v[k++] = v2[j++];
//            destroySphereMerge(v, k - 1);
//            su.addBranchGraph(respawnSphereMerge(v, k - 1));
//            sleep(2000);
        }

    }

    private static void bubbleThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            BubbleThread thread = new BubbleThread("Bubble");
            thread.start();
        }
    }

    private static void mergeThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            MergeThread thread = new MergeThread("Merge");
            thread.start();
        }
    }

    private static void insertionThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            InsertionThread thread = new InsertionThread("Insertion");
            thread.start();
        }
    }

    private static void shellThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            ShellThread thread = new ShellThread("Shell");
            thread.start();
        }
    }

    private static void stackThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            StackThread thread = new StackThread("Stack");
            thread.start();
        }
    }

    private static void queueThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            QueueThread thread = new QueueThread("Queue");
            thread.start();
        }
    }

    private static void vectorThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            VectorThread thread = new VectorThread("Vector");
            thread.start();
        }
    }

    private static void selectionThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            SelectionThread thread = new SelectionThread("Selection");
            thread.start();
        }
    }

    private static void listThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            ListThread thread = new ListThread("List");
            thread.start();
        }
    }

    private static void quickThreadCall() {

        if (!isRunning) {
            trace = 1;
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            QuickInPlaceThread thread = new QuickInPlaceThread("QuickInPlace");
            thread.start();
        }
    }

    private static void CountingThreadCall() {

        if (!isRunning) {
            isRunning = true;
            sc.setCorrect(0);
            sc.setTotal(0);
            CountingThread thread = new CountingThread("Counting");
            thread.start();
        }
    }

    public static void clearTexts() {
        textPane.setText(algoritmo);
        textPane2.setText(algoritmo2);
    }

    public static void callHelp() {

        JFrame helpFrame = new JFrame("Ajuda");
        helpFrame.setResizable(false);
        JPanel upperPanel = new JPanel(new FlowLayout());
        JButton bubbleButton = new JButton("BubbleSort");

        bubbleButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                helpText.setText(descricaoBubble);
            }
        });

        JButton selectionButton = new JButton("SelctionSort");

        selectionButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                helpText.setText(descricaoSelection);
            }
        });

        JButton insertionButton = new JButton("InsertionSort");

        insertionButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                helpText.setText(descricaoInsertion);
            }
        });

        JButton quickButton = new JButton("QuickSort");

        quickButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                helpText.setText(descricaoQuick);
            }
        });

        upperPanel.add(bubbleButton);
        upperPanel.add(selectionButton);
        upperPanel.add(insertionButton);
        upperPanel.add(quickButton);
        JScrollPane scrollPane = new JScrollPane();

        helpText = new JTextArea("Área de descrições.");
        helpText.setEditable(false);
        helpText.setRows(20);
        helpText.setColumns(15);
        helpText.setLineWrap(true);
        helpText.setAutoscrolls(true);

        scrollPane.setViewportView(helpText);

        helpFrame.add(upperPanel, BorderLayout.NORTH);
        helpFrame.add(scrollPane, BorderLayout.CENTER);

        //frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        helpFrame.setSize(450, 400);
        helpFrame.setVisible(true);
    }

    public static void changeQuestion(String a1, String a2, int response) {
        //Response 0 para true, 1 para false;
        Object options[] = {"Sim", "Não"};
        int randomizar = 99999;
        while (randomizar != response) {
            randomizar = JOptionPane.showOptionDialog(null, "Haverá a troca entre " + a1 + " e " + a2 + "?", "Questão", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
            if (randomizar == response) { //case true
                JOptionPane.showMessageDialog(null, "Resposta correta!");
            } else { //case false
                JOptionPane.showMessageDialog(null, "Resposta incorreta! \n Tente novamente.");
            }
        }

    }

    public static void quickInPlace(Number v[], int comeco, int fim) {

        if (comeco < fim) {

            Number pivot = v[fim];
            int i = comeco;
            int j = fim;

            while (i != j) {

                if (v[i].getNumber() < pivot.getNumber()) {

                    i = i + 1;

                } else {

                    v[j] = v[i];
                    v[i] = v[j - 1];
                    j = j - 1;

                }
            }

            v[j] = pivot;
            quickInPlace(v, comeco, j - 1);
            quickInPlace(v, j + 1, fim);
        }
    }

    public static void inPlaceQuickSort(Number v[], int comeco, int fim) {

        Number auxiliar;
        textPane2.setText("comeco = " + comeco + "\n fim = " + fim);
        highlightsText("se ( comeco >= fim ) {\n", textoQuick);

        if (comeco >= fim) {
            highlightsText("  retorne;\n", textoQuick);
            return;
        }
        highlightsText("pivo = v [ fim ];\n", textoQuick);
        int pivo = v[fim].getNumber();
        textPane2.setText("comeco = " + comeco + "\n fim = " + fim + "\n pivo = " + pivo);
        highlightsText("l = comeco;\n", textoQuick);
        int l = comeco;
        textPane2.setText("comeco = " + comeco + "\n fim = " + fim + "\n pivo = " + pivo + "\n l = " + l);
        highlightsText("r = fim - 1;\n\n", textoQuick);
        int r = fim - 1;
        textPane2.setText("comeco = " + comeco + "\n fim = " + fim + "\n pivo = " + pivo + "\n l = " + l
                + "\n r = " + r);

        highlightsText("enquanto( l <= r) {\n", textoQuick);
        while (l <= r) {

            highlightsText("  enquanto ( l <= r e v [ l ] <= pivo ) {\n", textoQuick);
            while (l <= r && v[l].getNumber() <= pivo) {
                highlightsText("     l++;\n", textoQuick);
                l++;
                textPane2.setText("comeco = " + comeco + "\n fim = " + fim + "\n pivo = " + pivo + "\n l = " + l
                        + "\n r = " + r);
            }

            highlightsText("  enquanto ( r >= l e v [ r ] >= pivo ) {\n", textoQuick);
            while (r >= l && v[r].getNumber() >= pivo) {
                highlightsText("     r--;\n", textoQuick);
                r--;
                textPane2.setText("comeco = " + comeco + "\n fim = " + fim + "\n pivo = " + pivo + "\n l = " + l
                        + "\n r = " + r);
            }

            highlightsText("  se ( l < r ) {\n", textoQuick);
            textPane2.setText("comeco = " + comeco + "\n fim = " + fim + "\n pivo = " + pivo + "\n l = " + l
                    + "\n r = " + r);

            /*
             * QUESTION BLOCK
             */
            if (l < r) {
                changeQuestion("l", "r", 0);
            } else {
                changeQuestion("l", "r", 1);
            }
            /*
             * QUESTION BLOCK
             */

            if (l < r) {
                //swap l e r
                if (r == -1 || r == 0) {
                    nextSwap(v, l, v[l].getNumber(), 0);
                } else {
                    nextSwap(v, l, v[l].getNumber(), r);

                    if (v[l].getNumber() != v[r].getNumber()) {
                        moverObjetoGeneric(v, l, r, "quick1");
                    }
                }


                auxiliar = v[l];
                v[l] = v[r];
                v[r] = auxiliar;

                textPane2.setText("comeco = " + comeco + "\n fim = " + fim + "\n pivo = " + pivo + "\n l = " + l
                        + "\n r = " + r + "\n auxiliar = " + auxiliar.getNumber() + "\n v [ l ] = " + v[l].getNumber()
                        + "\n v [ r ] = " + v[r].getNumber());

            }

        }

        //swap l e fim
        if (l != fim) {
            nextSwap(v, l, v[l].getNumber(), fim);
            moverObjetoGeneric(v, l, fim, "quick2");
        }

        auxiliar = v[l];
        v[l] = v[fim];
        v[fim] = auxiliar;

//        textPane2.setText("comeco = " + comeco + "\n fim = " + fim + "\n pivo = " + pivo + "\n l = " + l
//        + "\n r = " + r + "\n auxiliar = " + auxiliar.getNumber() + "\n v [ l ] = " + v[l].getNumber()
//        + "\n v [ r ] = " + v[r].getNumber());

        highlightsText("  inPlaceQuickSort(v, comeco, l - 1);\n", textoQuick);
        inPlaceQuickSort(v, comeco, l - 1);
        highlightsText("  inPlaceQuickSort(v, l + 1, fim);", textoQuick);
        inPlaceQuickSort(v, l + 1, fim);
    }

    public static void stackAnimation(Number v[]) {

        addBranchGroup();
        destroySphereMergeSecond(vetorNumeros, 0);
        su.addBranchGraph(respawnSphereMergeSecond(vetorNumeros, stackSize));
    }

    public static void stackPush(Number v[]) {
    }

    public static synchronized void numeroCorreto(Number v[], int atual, int correto) {
        boolean isValid = false;
        System.out.println("CORRETO = " + correto);
        do {
            String str = JOptionPane.showInputDialog("Número para troca atual = " + atual + ", qual"
                    + " será o número à ser trocado?");
            int numero = Integer.parseInt(str);
            System.out.println("O NUMERO LIDO FOI = " + numero);
            for (int i = 0; i < v.length; i++) {

                if (v[i].getNumber() == correto && v[i].getNumber() != atual) {
                    JOptionPane.showMessageDialog(null, "Correto!");
                    isValid = true;
                }

            }

            if (isValid == false) {
                JOptionPane.showMessageDialog(null, "Número de troca incorreto!");
            }

        } while (isValid == false);
    }

    public static void nextSwap(Number v[], int index_value, int number, int correct) {
        //vai receber o vetor, o indice do número atual para fazer a troca,
        //o numero atual em si e a | posição do numero correto | <- (daqui que vem o cálculo).


        if (correct == index_value) {
            return;
        }

        boolean isValid = false;
        List numbers = new ArrayList();
        System.out.println("Vector size = " + v.length);

        for (int i = 0; i < v.length; i++) {

            if (v[i].getNumber() != v[index_value].getNumber()) {
                numbers.add(v[i].getNumber());
            }

        }

        Object options[] = new Object[numbers.size()];

        Object correctAnswer = v[correct].getNumber();
        System.out.println("Correto = " + correctAnswer);
        System.out.println("index_value = " + index_value);
        System.out.println("number = " + number);
        System.out.println("Correto position = " + correct);

        if (correct == -1) {
            correct = v.length - 1;
        }

        for (int i = 0; i < numbers.size(); i++) {
            options[i] = numbers.get(i);
        }

        int tries = 0;
        sc.addTotal();
        do {
            int choice = JOptionPane.showOptionDialog(null, "Posição atual, definida por j = " + index_value + "\n Qual a próxima troca do número " + number + "?", "Questão", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);

            if (choice == -1) {
                removeElements(v);
            }

            if (options[choice] == correctAnswer) {
                if (tries == 0) {
                    sc.addCorrect();
                }
                isValid = true;
                JOptionPane.showMessageDialog(null, "Escolha correta!");

            } else {
                JOptionPane.showMessageDialog(null, "Escolha incorreta! \n Tente novamente.");
            }
            tries++;
        } while (isValid == false);

    }

    public static void selectionSortFinal(Number v[]) {

        int index_min;
        Number aux;

        textPane2.setText("Tamanho do vetor = " + v.length);
        highlightsText("para ( int i = 0; i < tamanho_vetor; i++ ) {\n\n", textoSelection);

        for (int i = 0; i < v.length; i++) {

            textPane2.setText("  i = " + i + "\n Tamanho do vetor = " + v.length);

            highlightsText("  index_min = i\n\n", textoSelection);
            index_min = i;
            textPane2.setText("  i = " + i + "\n index_min = " + index_min + "\n Tamanho do vetor = " + v.length);


            highlightsText("    para ( int j = i + 1; j < tamanho_vetor; j++ ) {\n\n", textoSelection);
            for (int j = i + 1; j < v.length; j++) {
                textPane2.setText("  i = " + i + "\n j = " + j + "\n index_min = " + index_min + "\n Tamanho do vetor = " + v.length);


                highlightsText("      se ( v [ j ] < v [ index_min ] ) {\n", textoSelection);
                if (v[j].getNumber() < v[index_min].getNumber()) {
                    highlightsText("      index_min = j;\n", textoSelection);
                    index_min = j;
                    textPane2.setText("  i = " + i + "\n j = " + j + "\n index_min = " + index_min + "\n Tamanho do vetor = " + v.length);

                }

            }
            highlightsText("    se ( index_min != i ) {\n\n", textoSelection);
            if (index_min != i) {


                nextSwap(v, index_min, v[index_min].getNumber(), i);
                moverObjetoGeneric(v, i, index_min, "selection");


                textPane2.setText("  i = " + i + "\n index_min = " + index_min + "\n Tamanho do vetor = " + v.length + "\n v[i] = " + v[i] + "\n v[index_min] = " + v[index_min]);
                aux = v[index_min];
                textPane2.setText("  i = " + i + "\n index_min = " + index_min + "\n Tamanho do vetor = " + v.length + "\n v[i] = " + v[i] + "\n v[index_min] = " + v[index_min] + "\n");
                v[index_min] = v[i];
                textPane2.setText("  i = " + i + "\n index_min = " + index_min + "\n Tamanho do vetor = " + v.length + "\n v[i] = " + v[i] + "\n v[index_min] = " + v[index_min] + "\n");
                v[i] = aux;
                textPane2.setText("  i = " + i + "\n index_min = " + index_min + "\n Tamanho do vetor = " + v.length + "\n v[i] = " + v[i] + "\n v[index_min] = " + v[index_min] + "\n");

            }

        }

        JOptionPane.showMessageDialog(null, "A ordenação foi concluída!");
        removeElements(v);
    }

    public static void bubbleSortFinal(Number v[]) {

//        textPane2.setText("i = ?\n j = ?\n Tamanho do vetor = ?\n");
        float[] posicoes = {-1.7f, 0.555f, 0.0f};
        int i = 0, j = 0;

        for (i = v.length; i >= 1; i--) {

            textPane2.setText(" i = " + i + "\n Tamanho do vetor = " + v.length + "\n");
            highlightsText("para ( i = tamanho_vetor; i >= 1; i-- ) { \n\n", textoBubble);

            try {
                Thread.sleep(500);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

            textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length + "\n");
            highlightsText("   para ( j = 1; j < i; j++ ) {\n\n", textoBubble);
            for (j = 1; j < i; j++) {

                try {
                    Thread.sleep(500);


                } catch (InterruptedException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
                textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length + "\n v [ j - 1 ] = " + v[j - 1].getNumber() + "\n v [ j ] = " + v[j].getNumber());
                highlightsText("      se ( v[ j - 1 ].valor( ) > v [ j ].valor( ) ) {\n", textoBubble);
                if (v[j - 1].getNumber() > v[j].getNumber()) {

                    try {
                        Thread.sleep(500);


                    } catch (InterruptedException ex) {
                        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                    }

//                    moverObjetoBubble(v, j - 1, j);
                    nextSwap(v, j, v[j].getNumber(), j - 1);
                    moverObjetoGeneric(v, j - 1, j, "bubble");

                    textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length + "\n v [ j - 1 ] = " + v[j - 1].getNumber() + "\n v [ j ] = " + v[j].getNumber()
                            + "\n auxiliar = " + v[j].getNumber());
                    Number aux = v[j];
                    textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length + "\n v [ j - 1 ] = " + v[j - 1].getNumber() + "\n v [ j ] = " + v[j].getNumber()
                            + "\n auxiliar = " + v[j].getNumber());
                    v[j] = v[j - 1];
                    textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length + "\n v [ j - 1 ] = " + v[j - 1].getNumber() + "\n v [ j ] = " + v[j].getNumber()
                            + "\n auxiliar = " + v[j].getNumber());
                    v[j - 1] = aux;

                }
            }
        }

        JOptionPane.showMessageDialog(null, "A ordenação foi concluída!");
        removeElements(v);

    }

    public static int getMinimumValue(Number vetor[]) {

        int minimumNumber = Integer.MAX_VALUE;

        for (Number number : vetor) {
            if (number.getNumber() <= minimumNumber) {
                minimumNumber = number.getNumber();
            }
        }

        return minimumNumber;
    }

    public static int getMaximumValue(Number vetor[]) {

        int maximumNumber = Integer.MIN_VALUE;

        for (Number number : vetor) {
            if (number.getNumber() >= maximumNumber) {
                maximumNumber = number.getNumber();
            }
        }

        return maximumNumber;
    }

    public static void countingSort(Number v[], int min, int max) {

        textPane2.setText("vetor.tamanho = " + v.length + "\n minimo = " + min + "\n maximo = " + max);

        for (Number n : v) {

            highlightsText("para (int i = 0; i < vetor.tamanho; i++) {\n\n", textoCounting);
            vetorCounting[n.getNumber() - min].setNumber(vetorCounting[n.getNumber() - min].getNumber() + 1);

            highlightsText(" vetorContagem[ vetorContagem[ i ] - minimo]++;\n\n", textoCounting);
            textPane2.setText("vetor.tamanho = " + v.length + "\n minimo = " + min + "\n maximo = " + max
                    + "\n vetorContagem[ vetorContagem [i ] - minimo ] = " + vetorCounting[n.getNumber() - min].getNumber());

            destroyBox(n.getNumber() - min);
            su.addBranchGraph(respawnBox(n.getNumber() - min));
            sleep(2000);
        }

        highlightsText("z = 0;\n\n", textoCounting);
        int j = 0;
        textPane2.setText("vetor.tamanho = " + v.length + "\n minimo = " + min + "\n maximo = " + max + "\n z = " + j);

        highlightsText("para (int i = minimo; i <= maximo; i++) {\n\n", textoCounting);
        for (int i = min; i <= max; i++) {

            textPane2.setText("vetor.tamanho = " + v.length + "\n minimo = " + min + "\n maximo = " + max + "\n z = " + j + "\n"
                    + " i = " + i);
            highlightsText("  enquanto (vetorContagem[i - minimo] > 0) {\n\n", textoCounting);
            while (vetorCounting[i - min].getNumber() > 0) {

                textPane2.setText("vetor.tamanho = " + v.length + "\n minimo = " + min + "\n maximo = " + max + "\n z = " + j + "\n"
                        + " i = " + i + "\n vetorContagem [ i - minimo ] = " + vetorCounting[i - min].getNumber());
                highlightsText("    vetor[ z ] = i;\n", textoCounting);
//                v[j].setNumber(i);
                //MUDANCA AQUI
                changeableVector[j].setNumber(i);

                textPane2.setText("vetor.tamanho = " + v.length + "\n minimo = " + min + "\n maximo = " + max + "\n z = " + j + "\n"
                        + " i = " + i + "\n vetorContagem [ i - minimo ] = " + vetorCounting[i - min].getNumber()
                        + "\n vetor[ z ] = " + v[j].getNumber());


                destroySphere(j);
                su.addBranchGraph(respawnSphere(j));
                sleep(2000);

                highlightsText("    z++;\n", textoCounting);
                j++;
                textPane2.setText("vetor.tamanho = " + v.length + "\n minimo = " + min + "\n maximo = " + max + "\n z = " + j + "\n"
                        + " i = " + i + "\n vetorContagem [ i - minimo ] = " + vetorCounting[i - min].getNumber());

                highlightsText("    vetorContagem[i - min]--;\n\n", textoCounting);
                vetorCounting[i - min].setNumber(vetorCounting[i - min].getNumber() - 1);
                textPane2.setText("vetor.tamanho = " + v.length + "\n minimo = " + min + "\n maximo = " + max + "\n z = " + j + "\n"
                        + " i = " + i + "\n vetorContagem [ i - minimo ] = " + vetorCounting[i - min].getNumber());

                destroyBox(i - min);
                su.addBranchGraph(respawnBox(i - min));
                sleep(2000);
            }
        }

    }

    public static void insertionSortFinal(Number v[]) {

        int i = 0, j = 0;
        Number aux;

        float[] posicoes = {-1.7f, 0.555f, 0.0f};

        textPane2.setText(" i = " + i + "\n Tamanho do vetor = " + v.length);
        highlightsText("para(i = 1; i < tamanho_vetor; i++){\n\n", textoInsertion);

        for (i = 1; i < v.length; i++) {

            try {
                Thread.sleep(500);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

            textPane2.setText(" i = " + i + "\n Tamanho do vetor = " + v.length);
            highlightsText("   j = i;\n\n", textoInsertion);
            j = i;


            try {
                Thread.sleep(500);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

            textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length
                    + "\n v [ j - 1 ] = " + v[j - 1].getNumber() + "\n v[j] = " + v[j].getNumber());
            highlightsText("      enquanto(v[ j ] < v[ j - 1 ]) {\n\n", textoInsertion);

            while (v[j].getNumber() < v[j - 1].getNumber()) {

                try {
                    Thread.sleep(500);


                } catch (InterruptedException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }

//                Scanner in = new Scanner(System.in);

                nextSwap(v, j, v[j].getNumber(), j - 1);
                moverObjetoGeneric(v, j - 1, j, "insertion");

                aux = v[j];
                textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length + "\n v [ j - 1 ] = "
                        + v[j - 1].getNumber() + "\n v[j] = " + v[j].getNumber() + "\n auxiliar = " + aux);
                v[j] = v[j - 1];
                textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length + "\n v [ j - 1 ] = "
                        + v[j - 1].getNumber() + "\n v[j] = " + v[j].getNumber() + "\n auxiliar = " + aux);
                v[j - 1] = aux;
                textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length + "\n v [ j - 1 ] = "
                        + v[j - 1].getNumber() + "\n v[j] = " + v[j].getNumber() + "\n auxiliar = " + aux);
//                highlightsText("         v[ j - 1 ] = auxiliar;\n", textoInsertion);

                try {
                    Thread.sleep(500);


                } catch (InterruptedException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }

                highlightsText("         j--.\n\n", textoInsertion);
                j--;
                textPane2.setText(" i = " + i + "\n j = " + j + "\n Tamanho do vetor = " + v.length);

                highlightsText("         se(j == 0) quebrar o laço;\n\n", textoInsertion);
                if (j == 0) {
                    break;
                }
            }
        }

        JOptionPane.showMessageDialog(null, "A ordenação foi concluída!");
        removeElements(v);

    }

    private static JTextPane createTextPane(String code) {
        StyledDocument style = new DefaultStyledDocument();
        JTextPane text = new JTextPane(style);
        text.setPreferredSize(new Dimension(400, 800));
        text.setText(code);
        text.setEditable(false);
        return text;
    }

    private static JTextPane createTextPaneDescricao(String code) {
        StyledDocument style = new DefaultStyledDocument();
        JTextPane text = new JTextPane(style);
        text.setPreferredSize(new Dimension(400, 200));
        text.setText(code);
        text.setEditable(false);
        return text;
    }

    public static void sleep(long sleepTime) {

        try {
            Thread.sleep(sleepTime);


        } catch (InterruptedException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void highlightsText(String string, String code) {
        textPane.getStyledDocument().setCharacterAttributes(0, code.length(), defaultText, true);
        int i = code.indexOf(string);
        textPane.getStyledDocument().setCharacterAttributes(i, string.length(), highlightedText, true);
        sleep(40 * 30);
    }

    public static void highlightsTextWithoutSleep(String string, String code) {
        textPane.getStyledDocument().setCharacterAttributes(0, code.length(), defaultText, true);
        int i = code.indexOf(string);
        textPane.getStyledDocument().setCharacterAttributes(i, string.length(), highlightedText, true);
    }

    public Main(JFrame f) {
        Main.frame = f;
    }

    public Main() {
        
    }
    
    
    public void init(JFrame frame){
       Main.frame = frame;
       addJanela();
    }

    public static JFrame addJanela() {

        frame = new JFrame("Sorting");
        //frame.setTitle("Sorting");

        StyleConstants.setForeground(defaultText, Color.black);
        StyleConstants.setBackground(defaultText, Color.white);

        StyleConstants.setForeground(highlightedText, Color.GREEN);
        StyleConstants.setBackground(highlightedText, Color.BLUE);

        frame.getContentPane().setLayout(new BorderLayout());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
        Canvas3D canvas = new Canvas3D(config);
        frame.getContentPane().add(BorderLayout.CENTER, canvas);


        textPane = createTextPane(algoritmo);
        textPane2 = createTextPaneDescricao(algoritmo2);


        panel = new JPanel();
        panel.setSize(400, 1000);
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        JScrollPane scroll = new JScrollPane(textPane);
        panel.add(scroll);

        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("Opções");
        JMenuItem menuAjuda = new JMenuItem("Ajuda");

        menuAjuda.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                callHelp();
            }
        });

        menu.add(menuAjuda);
        menuBar.add(menu);
        frame.add(menuBar, BorderLayout.NORTH);


        frame.getContentPane().add(BorderLayout.WEST, panel);

        panel.add(textPane2);

        JButton bubbleButton = new JButton("Bubble Sort");

        bubbleButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                bubbleThreadCall();
            }
        });

        JButton insertButton = new JButton("Insertion Sort");

        insertButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                insertionThreadCall();
            }
        });

        JButton selectionButton = new JButton("Selection Sort");

        selectionButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                selectionThreadCall();
            }
        });

        JButton inPlaceButton = new JButton("In-Place Quick Sort");

        inPlaceButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                quickThreadCall();
            }
        });

        JButton countingButton = new JButton("Counting Sort");

        countingButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                CountingThreadCall();
            }
        });

        JButton shellButton = new JButton("Shell Sort");

        shellButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                shellThreadCall();
            }
        });

        JButton mergeButton = new JButton("Merge Sort");

        mergeButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                mergeThreadCall();

            }
        });

        JButton stackButton = new JButton("Stack");

        stackButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                stackThreadCall();

            }
        });

        JButton queueButton = new JButton("Queue");

        queueButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                queueThreadCall();
            }
        });

        JButton vectorButton = new JButton("Vector");

        vectorButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                vectorThreadCall();
            }
        });

        JButton listButton = new JButton("List");

        listButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                listThreadCall();
            }
        });


        buttonPanel = new JPanel(new GridLayout(5, 2));
        buttonPanel.setPreferredSize(new Dimension(100, 65));
        buttonPanel.add(bubbleButton);
        buttonPanel.add(insertButton);
        buttonPanel.add(selectionButton);
        buttonPanel.add(inPlaceButton);
        buttonPanel.add(countingButton);
        buttonPanel.add(shellButton);
        buttonPanel.add(stackButton);
        buttonPanel.add(queueButton);
        buttonPanel.add(vectorButton);
        buttonPanel.add(listButton);

        panel.add(buttonPanel);

        su = new SimpleUniverse(canvas);
        background(su);
        su.getViewingPlatform().setNominalViewingTransform();

        OrbitBehavior orbital = new OrbitBehavior(canvas);
        orbital.setSchedulingBounds(new BoundingSphere(new Point3d(0.0, 0.0, 0.0), Double.MAX_VALUE));
        su.getViewingPlatform().setViewPlatformBehavior(orbital);

        frame.setSize(1200, 740);
        frame.setVisible(true);

        return frame;

    }

    public static Appearance addAparencia() {

        Appearance aparencia = new Appearance();
        //Aqui, faz com que a aparencia possa ser alterada, caso necessário.
        aparencia.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ);
        aparencia.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);

        //Cria o vetor da cor.
        Color3f cor = new Color3f(0.3f, 0.5f, 0.8f);

        //Aqui, define a cor da aparencia, no caso a da esfera.
        aparencia.setColoringAttributes(new ColoringAttributes(cor, selectionNumber));

        return aparencia;
    }

    public static Appearance addAparenciaGreen() {

        Appearance aparencia = new Appearance();
        //Aqui, faz com que a aparencia possa ser alterada, caso necessário.
        aparencia.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ);
        aparencia.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);

        //Cria o vetor da cor.
        Color3f cor = new Color3f(0.8f, 1.2f, 0.3f);

        //Aqui, define a cor da aparencia, no caso a da esfera.
        aparencia.setColoringAttributes(new ColoringAttributes(cor, selectionNumber));

        return aparencia;
    }

    public static Appearance addAparenciaBoxes() {

        Appearance aparencia = new Appearance();
        //Aqui, faz com que a aparencia possa ser alterada, caso necessário.
        aparencia.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ);
        aparencia.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);

        //Cria o vetor da cor.
        Color3f cor = new Color3f(0.3f, 0.9f, 1.1f);

        //Aqui, define a cor da aparencia, no caso a da esfera.
        aparencia.setColoringAttributes(new ColoringAttributes(cor, selectionNumber));

        return aparencia;
    }

    private static Texture criarImagem() {

        TextureLoader carregador = new TextureLoader("tex3.jpg", null);

        ImageComponent2D componenteImagem = carregador.getScaledImage(1024, 1024);

        Texture2D textura2D = new Texture2D(Texture2D.BASE_LEVEL, Texture2D.RGB, componenteImagem.getWidth(), componenteImagem.getHeight());
        textura2D.setImage(0, componenteImagem);
        return textura2D;
    }

    private static Texture criarImagemCustom() {

        TextureLoader carregador = new TextureLoader("leaf.jpg", null);

        ImageComponent2D componenteImagem = carregador.getScaledImage(1024, 1024);

        Texture2D textura2D = new Texture2D(Texture2D.BASE_LEVEL, Texture2D.RGB, componenteImagem.getWidth(), componenteImagem.getHeight());
        textura2D.setImage(0, componenteImagem);
        return textura2D;
    }

    public static Appearance criarApp() {

        Appearance app = new Appearance();

        app.setTexture(criarImagem());

        TextureAttributes texAttribute = new TextureAttributes();
        texAttribute.setTextureMode(TextureAttributes.REPLACE);
        app.setTextureAttributes(texAttribute);

        Material material = new Material();

        material.setShininess(200.0f);
        app.setMaterial(material);

        TexCoordGeneration coordenada = new TexCoordGeneration(TexCoordGeneration.OBJECT_LINEAR, TexCoordGeneration.TEXTURE_COORDINATE_2);
        app.setTexCoordGeneration(coordenada);

        return app;
    }

    public static Appearance criarAppCustom() {

        Appearance app = new Appearance();

        app.setTexture(criarImagemCustom());

        TextureAttributes texAttribute = new TextureAttributes();
        texAttribute.setTextureMode(TextureAttributes.REPLACE);
        app.setTextureAttributes(texAttribute);

        Material material = new Material();

        material.setShininess(200.0f);
        app.setMaterial(material);

        TexCoordGeneration coordenada = new TexCoordGeneration(TexCoordGeneration.OBJECT_LINEAR, TexCoordGeneration.TEXTURE_COORDINATE_2);
        app.setTexCoordGeneration(coordenada);

        return app;
    }

    public static BranchGroup textoAuxiliar() {

        BranchGroup bgValores = new BranchGroup();
//        Transform3D tfValores = new Transform3D();
//        tfValores.setTranslation(new Vector3f(-3.0f, -3.0f, 0.0f));

        int x = 0;
        float posicao = -0.8f;
        float posicao2 = 1.6f;

        for (int i = 0; i < 1; i++) {
            Transform3D tfTexto = new Transform3D();
            tfTexto.setTranslation(new Vector3f(posicao, posicao2, 0.0f));
            posicao += 1.4f;

            TransformGroup tgTexto = new TransformGroup(tfTexto);
            tgTexto.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
            bgValores.addChild(tgTexto);

            vetorValores[i] = new Texto(retornaValores(x, 0, 0, 0, 0, 0, 0), tgTexto);
            x++;
        }

        return (bgValores);

    }

    public static void background(SimpleUniverse su) {

        BranchGroup bgBack = new BranchGroup();

        TransformGroup tgBack = new TransformGroup();

        TextureLoader tex2 = new TextureLoader("background.jpg", null);

        Background bg2 = new Background();
        bg2.setImage(tex2.getImage());

        bg2.setImageScaleMode(Background.SCALE_FIT_ALL);
        bg2.setApplicationBounds(new BoundingSphere());

        tgBack.addChild(bg2);
        bgBack.addChild(tgBack);
        su.addBranchGraph(bgBack);
    }

    private static String retornaValores(int index, int t, int i, int j, int aux, int vj, int vj1) {

        String valores[] = new String[6];
        valores[0] = "tamanho_vetor = " + t;
        valores[1] = "i = " + i;
        valores[2] = "j = " + j;
        valores[3] = "v[" + j + "] = " + vj;
        valores[4] = "v[" + j + " - 1] = " + vj1;
        valores[5] = "auxiliar = " + aux;

        String nome = "";
        //return valores[index];
        if (sortingNumber == 0) {
            nome = "BUBBLE SORT";
        } else if (sortingNumber == 1) {
            nome = "INSERTION SORT";
        } else {
            nome = "SELECTION SORT";
        }

        return nome;

    }

    private static void exitProgram() {
        System.exit(0);
    }

    public static BranchGroup addBranchGroup() {

        BranchGroup branchGroup = new BranchGroup();
        //Aqui, joga a aparencia das esferas na Aparencia atual.

        Appearance aparencia = addAparencia();
        String number = "";
        while (selectionNumber > 10 || selectionNumber < 2 || number == null || number.equals("")) {
            number = JOptionPane.showInputDialog("Quantos elementos você deseja? (Mínimo = 2 / Máximo = 10)");
            if (number == null || number.equals("")) {
            } else {
                selectionNumber = Integer.parseInt(number);
            }
            if (selectionNumber == 0) {
                exitProgram();
            }

        }

        vetorNumeros = new Number[selectionNumber];
        boolean random;

        Object options[] = {"Sim", "Não"};
        int randomizar = JOptionPane.showOptionDialog(null, "Gerar números aleatórios?", "Randomizer", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
        if (randomizar == 0) {
            random = true;
        } else {
            random = false;
        }
        float posicao;
//        float posicao = (float) 0.4 * (raio * selectionNumber - raio);
        if (selectionNumber > 8) {
            posicao = -0.09f * selectionNumber;
        } else {
            posicao = -0.08f * selectionNumber;
        }
        System.out.println("Posicao dos elementos = " + posicao);
        //Aqui, recebe o número de elementos do vetor.

        int j = selectionNumber;

        for (int i = 0; i < selectionNumber; i++) {

            //Cria as esferas com o mesmo raio e a aparência recebida acima.
            Sphere esfera = new Sphere(raio, criarApp());

            //Aqui, permite que a esfera possa se mover/ser escrita, entre outros.
            esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

            //Aqui, cria os transforms3D de cada esfera e define seu posicionamento,
            Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
            tfEsfera.setTranslation(new Vector3f(posicao, 0.0f, 0.0f));
            posicao += raio * 2 + distancia;

            //Aqui, cria o transform group que vai conter as esferas.
            TransformGroup tgEsfera = new TransformGroup(tfEsfera);
            tgEsfera.addChild(esfera);
            branchGroup.addChild(tgEsfera);

            int numberTempInt;
            //Aqui, adiciona o objeto à cada posição do vetor, no caso, todos invertidos para demonstrar o
            if (random == false) {
                String numberTemp = JOptionPane.showInputDialog("Digite o próximo elemento:");
                numberTempInt = Integer.parseInt(numberTemp);
            } else {
                numberTempInt = 1 + (int) (Math.random() * 9);
            }
            vetorNumeros[i] = new Number(numberTempInt, tgEsfera); //algoritmo inteiro.
            j--;
        }

        return branchGroup;
    }

    public static BranchGroup addCustomBranchGroup(Number v[], int size, float coordX, float coordY) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();
        String number = "";

//        v = new Number[size];

        float posicao = (float) 0.4 * (raio * size - raio);
        System.out.println("Posicao dos elementos = " + posicao);

        int j = size;

        for (int i = 0; i < size; i++) {

            //Cria as esferas com o mesmo raio e a aparência recebida acima.
            Sphere esfera = new Sphere(raio, criarApp());

            //Aqui, permite que a esfera possa se mover/ser escrita, entre outros.
            esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

            //Aqui, cria os transforms3D de cada esfera e define seu posicionamento,
            Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
            tfEsfera.setTranslation(new Vector3f(coordX, coordY, 0.0f));
            coordX += raio * 2 + distancia;

            //Aqui, cria o transform group que vai conter as esferas.
            TransformGroup tgEsfera = new TransformGroup(tfEsfera);
            tgEsfera.addChild(esfera);
            branchGroup.addChild(tgEsfera);

            //Ver os numeros aqui.
            v[i] = new Number(v[i].getNumber(), tgEsfera); //algoritmo inteiro.
            j--;
        }


        return branchGroup;
    }

    public static BranchGroup addCountingBranchGroup() {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        String number = "";

        while (selectionNumber > 8 || selectionNumber < 2 || number == null || number.equals("")) {
            number = JOptionPane.showInputDialog("Quantos elementos você deseja? (Mínimo = 2 / Máximo = 8)");
            if (number == null || number.equals("")) {
            } else {
                selectionNumber = Integer.parseInt(number);
            }
            if (selectionNumber == 0) {
                exitProgram();
            }

        }

        vetorNumeros = new Number[selectionNumber];
        changeableVector = new Number[selectionNumber];

        boolean random;

        Object options[] = {"Sim", "Não"};
        int randomizar = JOptionPane.showOptionDialog(null, "Gerar números aleatórios?", "Randomizer", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
        if (randomizar == 0) {
            random = true;
        } else {
            random = false;
        }

//        float posicao = (float) 0.4 * (raio * selectionNumber - raio);
        float posicao;
        if (selectionNumber > 8) {
            posicao = -0.09f * selectionNumber;
        } else {
            posicao = -0.08f * selectionNumber;
        }
        System.out.println("Posicao dos elementos = " + posicao);

        int j = selectionNumber;

        for (int i = 0; i < selectionNumber; i++) {

            Sphere esfera = new Sphere(raio, criarApp());
            esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

            Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
            tfEsfera.setTranslation(new Vector3f(posicao, 0.5f, 0.0f));
            posicao += raio * 2 + distancia;

            TransformGroup tgEsfera = new TransformGroup(tfEsfera);
            tgEsfera.addChild(esfera);
            branchGroup.addChild(tgEsfera);

            int numberTempInt;

            if (random == false) {
                String numberTemp = JOptionPane.showInputDialog("Digite o próximo elemento:");
                numberTempInt = Integer.parseInt(numberTemp);
            } else {
                numberTempInt = 1 + (int) (Math.random() * 9);
            }
            vetorNumeros[i] = new Number(numberTempInt, tgEsfera);
            j--;
        }

        if (selectionNumber > 8) {
            posicao = -0.09f * selectionNumber;
        } else {
            posicao = -0.08f * selectionNumber;
        }

        j = selectionNumber;

        for (int i = 0; i < selectionNumber; i++) {

            Sphere esfera = new Sphere(raio, criarApp());
            esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

            Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
            tfEsfera.setTranslation(new Vector3f(posicao, 0.0f, 0.0f));
            posicao += raio * 2 + distancia;

            TransformGroup tgEsfera = new TransformGroup(tfEsfera);
            tgEsfera.addChild(esfera);
            branchGroup.addChild(tgEsfera);


            changeableVector[i] = new Number(0, tgEsfera);
            j--;
        }



        int min = getMinimumValue(vetorNumeros);
        int max = getMaximumValue(vetorNumeros);

//        Quantos elementos h

        vetorCounting = new Number[max - min + 1];

        askLength(vetorNumeros, max - min + 1);


//        posicao = (float) 0.4 * (raio * selectionNumber - raio);
//        posicao -= 0.2f;

        if (vetorCounting.length > 7) {
            posicao = -0.09f * selectionNumber;
        } else {
            posicao = -0.08f * selectionNumber;
        }

        Vector3f radius = new Vector3f(0.1f, 0.1f, 0.1f);
//        su.getViewingPlatform().getViewPlatformBehavior().


        for (int i = 0; i < vetorCounting.length; i++) {

//            Box caixa = new Box(0.1f, 0.1f, 0.1f, criarApp());
            Box caixa = new Box(radius.x, radius.y, radius.z, criarApp());
            caixa.setCapability(Box.ENABLE_APPEARANCE_MODIFY);

            Transform3D tfCaixa = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
            tfCaixa.setTranslation(new Vector3f(posicao, -0.5f, 0.0f));
            posicao += raio * 2 + distancia;
            posicao += 0.03f;

            TransformGroup tgCaixa = new TransformGroup(tfCaixa);
            tgCaixa.addChild(caixa);
            branchGroup.addChild(tgCaixa);


            vetorCounting[i] = new Number(0, tgCaixa);

        }

        return branchGroup;

    }

    public static void askLength(Number[] v, int rightNumber) {

        boolean isValid = false;

        Object options[] = new Object[5];

        int random = (int) (Math.random() * 5);

        for (int i = 0; i < 5; i++) {
            int random2 = (int) (Math.random() * 5);

            if (i == random) {
                options[i] = rightNumber;
            } else {
                options[i] = rightNumber + i + random2;
            }
        }

        Object correctOption = rightNumber;

        String numbers = null;
        numbers = "{ ";
        for (int i = 0; i < v.length; i++) {
            numbers += v[i].numero + " ";
        }
        numbers += "}";

        int tries = 0;
        sc.addTotal();

        do {
            int choice = JOptionPane.showOptionDialog(null, "Vetor atual: " + numbers + "\nQual será o tamanho do vetor de contagem??", "Questão", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);

            if (options[choice] == correctOption) {
                if (tries == 0) {
                    sc.addCorrect();
                }
                isValid = true;
                JOptionPane.showMessageDialog(null, "Escolha correta!");

            } else {
                JOptionPane.showMessageDialog(null, "Escolha incorreta! \n Tente novamente.");
            }
            tries++;
        } while (isValid == false);

    }

    public static BranchGroup recreateSpheres() {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();


        float posicao = (float) 0.4 * (raio * selectionNumber - raio);

        int j = selectionNumber;

        for (int i = 0; i < selectionNumber; i++) {

            Sphere esfera = new Sphere(raio, criarApp());
            esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

            Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
            tfEsfera.setTranslation(new Vector3f(posicao, 0.0f, 0.0f));
            posicao += raio * 2 + distancia;

            TransformGroup tgEsfera = new TransformGroup(tfEsfera);
            tgEsfera.addChild(esfera);
            branchGroup.addChild(tgEsfera);


            vetorNumeros[i] = new Number(vetorNumeros[i].getNumber(), tgEsfera);
            j--;
        }

        return branchGroup;
    }

    public static BranchGroup recreateBoxes() {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        float posicao = (float) 0.4 * (raio * selectionNumber - raio);
        posicao -= 0.2f;

        for (int i = 0; i < vetorCounting.length; i++) {


            Box caixa = new Box(0.1f, 0.1f, 0.1f, criarApp());
            caixa.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

            Transform3D tfCaixa = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
            tfCaixa.setTranslation(new Vector3f(posicao, -0.5f, 0.0f));
            posicao += raio * 2 + distancia;
            posicao += 0.03f;

            TransformGroup tgCaixa = new TransformGroup(tfCaixa);
            tgCaixa.addChild(caixa);
            branchGroup.addChild(tgCaixa);
            vetorCounting[i] = new Number(vetorCounting[i].getNumber(), tgCaixa);


        }

        return branchGroup;
    }

    public static void destroyBox(int index) {

        TransformGroup tGroup = vetorCounting[index].getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static void destroySphere(int index) {

        TransformGroup tGroup = changeableVector[index].getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static void destroyShellSphere(int index) {

        TransformGroup tGroup = vetorNumeros[index].getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static void destroyShellSphereCustom(Number v[], int index) {

        TransformGroup tGroup = v[index].getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static BranchGroup respawnShellSphere(int index) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Sphere esfera = new Sphere(raio, criarApp());
        esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        tfEsfera.setTranslation(tempPosition);

        TransformGroup tgEsfera = new TransformGroup(tfEsfera);
        tgEsfera.addChild(esfera);
        branchGroup.addChild(tgEsfera);

        vetorNumeros[index] = new Number(vetorNumeros[index].getNumber(), tgEsfera);

        return branchGroup;

    }

    public static BranchGroup respawnShellSphere(int index, Vector3f positions) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Sphere esfera = new Sphere(raio, criarApp());
        esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        Vector3f tempPos = shellPositions;

        if (index == 0) {
            tempPos.x = -0.32f;
        } else {
            tempPos.x = (index * 0.2f) - 0.32f;
        }

        tfEsfera.setTranslation(tempPos);

        TransformGroup tgEsfera = new TransformGroup(tfEsfera);
        tgEsfera.addChild(esfera);
        branchGroup.addChild(tgEsfera);

        vetorNumeros[index] = new Number(vetorNumeros[index].getNumber(), tgEsfera);

        return branchGroup;

    }

    public static BranchGroup respawnShellSphereCustom(Number v[], int index, Vector3f positions) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Sphere esfera = new Sphere(raio, criarApp());
        esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        Vector3f tempPos = shellPositions;

        if (index == 0) {
            tempPos.x = -0.32f;
        } else {
            tempPos.x = (index * 0.2f) - 0.32f;
        }

        tfEsfera.setTranslation(tempPos);

        TransformGroup tgEsfera = new TransformGroup(tfEsfera);
        tgEsfera.addChild(esfera);
        branchGroup.addChild(tgEsfera);

        v[index] = new Number(v[index].getNumber(), tgEsfera);

        return branchGroup;

    }

    public static BranchGroup respawnSphere(int index) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Sphere esfera = new Sphere(raio, criarApp());
        esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        tfEsfera.setTranslation(tempPosition);

        TransformGroup tgEsfera = new TransformGroup(tfEsfera);
        tgEsfera.addChild(esfera);
        branchGroup.addChild(tgEsfera);

        changeableVector[index] = new Number(changeableVector[index].getNumber(), tgEsfera);

        return branchGroup;

    }

    public static void destroyListElement(int index) {

        TransformGroup tGroup = numberList.get(index).getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);


    }

    public static void destroySphereGeneric(Number v[], int index) {

        TransformGroup tGroup = v[index].getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static void destroyQueueObject(List<Number> list, int index) {

        TransformGroup tGroup = list.get(index).getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }
    
    public static void destroyVectorElement(Number v[], int index) {

        TransformGroup tGroup = v[index].getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static void destroyVectorObject(List<Number> list, int index) {

        TransformGroup tGroup = list.get(index).getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static void destroySphereStack(int index) {

        TransformGroup tGroup = vetorNumeros[index].getTGNumber();
        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }
    
    public static BranchGroup respawnSphereVector(Number v[], int index, Vector3f positions) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Sphere esfera = new Sphere(raio, criarApp());
        esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        tfEsfera.setTranslation(positions);

        TransformGroup tgEsfera = new TransformGroup(tfEsfera);
        tgEsfera.addChild(esfera);
        branchGroup.addChild(tgEsfera);

        v[index] = new Number(v[index].getNumber(), tgEsfera);

        return branchGroup;

    }

    public static BranchGroup respawnSphereGeneric(Number v[], int index) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Sphere esfera = new Sphere(raio, criarApp());
        esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        tfEsfera.setTranslation(tempPosition);

        TransformGroup tgEsfera = new TransformGroup(tfEsfera);
        tgEsfera.addChild(esfera);
        branchGroup.addChild(tgEsfera);

        v[index] = new Number(v[index].getNumber(), tgEsfera);

        return branchGroup;

    }

    public static void destroySphereMerge(Number v[], int index) {
        TransformGroup tGroup = null;

        if (mergeCallStack == 1) {
            tGroup = vetorNumeros[index].getTGNumber();
        } else if (mergeCallStack == 2) {
            tGroup = firstSubVector[index].getTGNumber();
        } else if (mergeCallStack == 3) {
            tGroup = fsvSubVector2[index].getTGNumber();
        } else if (mergeCallStack == 4) {
            tGroup = secondSubVector[index].getTGNumber();
        } else if (mergeCallStack == 5) {
            tGroup = ssvssSubVector2[index].getTGNumber();
        }

        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static void destroySphereMergeFirst(Number v[], int index) {
        TransformGroup tGroup = null;

        if (mergeCallStack == 1) {
            tGroup = firstSubVector[index].getTGNumber();
        } else if (mergeCallStack == 2) {
            tGroup = fsvSubVector1[index].getTGNumber();
        } else if (mergeCallStack == 3) {
            tGroup = fsvssSubVector1[index].getTGNumber();
        } else if (mergeCallStack == 4) {
            tGroup = ssvSubVector1[index].getTGNumber();
        } else if (mergeCallStack == 5) {
            tGroup = ssvssSubVector1[index].getTGNumber();
        }

        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static void destroySphereMergeSecond(Number v[], int index) {
        TransformGroup tGroup = null;

        if (mergeCallStack == 1) {
            tGroup = secondSubVector[index].getTGNumber();
        } else if (mergeCallStack == 2) {
            tGroup = fsvSubVector2[index].getTGNumber();
        } else if (mergeCallStack == 3) {
            tGroup = fsvssSubVector2[index].getTGNumber();
        } else if (mergeCallStack == 4) {
            tGroup = ssvSubVector2[index].getTGNumber();
        } else if (mergeCallStack == 5) {
            tGroup = ssvssSubVector2[index].getTGNumber();
        }

        Transform3D tForm = new Transform3D();
        tGroup.getTransform(tForm);

        Vector3f translation = new Vector3f();
        tForm.get(translation);
        tempPosition = new Vector3f(translation);

        translation.z = 9999999999f;
        tForm.setTranslation(translation);
        tGroup.setTransform(tForm);

    }

    public static BranchGroup respawnSphereMerge(Number v[], int index) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Sphere esfera = new Sphere(raio, criarApp());
        esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        tfEsfera.setTranslation(tempPosition);

        TransformGroup tgEsfera = new TransformGroup(tfEsfera);
        tgEsfera.addChild(esfera);
        branchGroup.addChild(tgEsfera);

        if (mergeCallStack == 1) {

            vetorNumeros[index] = new Number(vetorNumeros[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 2) {
            firstSubVector[index] = new Number(firstSubVector[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 3) {
            fsvSubVector2[index] = new Number(fsvSubVector2[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 4) {
            secondSubVector[index] = new Number(secondSubVector[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 5) {
            ssvSubVector2[index] = new Number(ssvSubVector2[index].getNumber(), tgEsfera);
        }

        return branchGroup;

    }

    public static BranchGroup respawnSphereMergeFirst(Number v[], int index) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Sphere esfera = new Sphere(raio, criarApp());
        esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        tfEsfera.setTranslation(tempPosition);

        TransformGroup tgEsfera = new TransformGroup(tfEsfera);
        tgEsfera.addChild(esfera);
        branchGroup.addChild(tgEsfera);

        if (mergeCallStack == 1) {

            firstSubVector[index] = new Number(firstSubVector[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 2) {
            fsvSubVector1[index] = new Number(fsvSubVector1[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 3) {
            fsvssSubVector1[index] = new Number(fsvssSubVector1[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 4) {
            ssvSubVector1[index] = new Number(ssvSubVector1[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 5) {
            ssvssSubVector1[index] = new Number(ssvssSubVector1[index].getNumber(), tgEsfera);
        }

        return branchGroup;

    }

    public static BranchGroup respawnSphereMergeSecond(Number v[], int index) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Sphere esfera = new Sphere(raio, criarApp());
        esfera.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfEsfera = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        tfEsfera.setTranslation(tempPosition);

        TransformGroup tgEsfera = new TransformGroup(tfEsfera);
        tgEsfera.addChild(esfera);
        branchGroup.addChild(tgEsfera);

        if (mergeCallStack == 1) {

            secondSubVector[index] = new Number(secondSubVector[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 2) {
            fsvSubVector2[index] = new Number(fsvSubVector2[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 3) {
            fsvssSubVector2[index] = new Number(fsvssSubVector2[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 4) {
            ssvSubVector2[index] = new Number(ssvSubVector2[index].getNumber(), tgEsfera);
        } else if (mergeCallStack == 5) {
            ssvssSubVector2[index] = new Number(ssvssSubVector2[index].getNumber(), tgEsfera);
        }

        return branchGroup;

    }

    public static BranchGroup respawnBox(int index) {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        Box caixa = new Box(0.1f, 0.1f, 0.1f, criarApp());
        caixa.setCapability(Sphere.ENABLE_APPEARANCE_MODIFY);

        Transform3D tfCaixa = new Transform3D(); // logo após, incrementando a distância para a próxima esfera.
        tfCaixa.setTranslation(tempPosition);


        TransformGroup tgCaixa = new TransformGroup(tfCaixa);
        tgCaixa.addChild(caixa);
        branchGroup.addChild(tgCaixa);
        vetorCounting[index] = new Number(vetorCounting[index].getNumber(), tgCaixa);

        return branchGroup;

    }

    public static float getPosition() {

        float position = 0;

        if (selectionNumber == 2) {
            position = (float) (-2.5 * (raio * selectionNumber - raio) - 2.7f);
        } else if (selectionNumber == 3) {
            position = (float) (-2.5 * (raio * selectionNumber - raio) - 2.2f);
        } else if (selectionNumber == 4) {
            position = (float) (-2.5 * (raio * selectionNumber - raio) - 1.7f);
        } else if (selectionNumber == 5) {
            position = (float) (-2.5 * (raio * selectionNumber - raio) - 1.2f);
        } else if (selectionNumber == 6) {
            position = (float) (-2.5 * (raio * selectionNumber - raio) - 0.7f);
        } else if (selectionNumber == 7) {
            position = (float) (-2.5 * (raio * selectionNumber - raio) - 0.2f);
        } else if (selectionNumber == 8) {
            position = (float) (-2.5 * (raio * selectionNumber - raio) + 0.2f);
        } else {
            position = (float) (-2.5 * (raio * selectionNumber - raio) + 0.9f);
        }

        return position;
    }

    public static void virtualStack(int capacity) {

        vetorNumeros = new Number[capacity];
    }

    public static BranchGroup stackBranchGroup() {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        String stackCapacityS = "";
        int capacityNumber = 0;

        while (capacityNumber == 0 || capacityNumber > 5 || capacityNumber < 2 || stackCapacityS == null || stackCapacityS.equals("")) {
            stackCapacityS = JOptionPane.showInputDialog("Qual a capacidade da pilha? (Mínimo = 2 / Máximo = 5)");
            if (stackCapacityS == null || stackCapacityS.equals("")) {
            } else {
                capacityNumber = Integer.parseInt(stackCapacityS);
            }

        }
        capacity = capacityNumber;
        virtualStack(capacity);
        stackCapacity = capacity;
        textPane.setText(textoStack);
        return branchGroup;
    }

    public static BranchGroup queueBranchGroup() {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        String listCapacityS = "";
        int capacityNumber = 0;

        while (capacityNumber == 0 || capacityNumber > 5 || capacityNumber < 2 || listCapacityS == null || listCapacityS.equals("")) {
            listCapacityS = JOptionPane.showInputDialog("Qual a capacidade da Fila? (Mínimo = 2 / Máximo = 5)");
            if (listCapacityS == null || listCapacityS.equals("")) {
            } else {
                capacityNumber = Integer.parseInt(listCapacityS);
            }

        }

        queueCapacity = capacityNumber;
        queueSize = 0;

        numberList = new ArrayList<Number>(queueCapacity);

        return branchGroup;
    }

    public static BranchGroup vectorBranchGroup() {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

        String vectorCapacityS = "";
        int capacityNumber = 0;

        while (capacityNumber == 0 || capacityNumber > 4 || capacityNumber < 2 || vectorCapacityS == null || vectorCapacityS.equals("")) {
            vectorCapacityS = JOptionPane.showInputDialog("Qual a capacidade do vetor? (Mínimo = 2 / Máximo = 4)");
            if (vectorCapacityS == null || vectorCapacityS.equals("")) {
            } else {
                capacityNumber = Integer.parseInt(vectorCapacityS);
            }

        }

        vectorShadowList = new ArrayList<Number>();

        for (int i = 0; i < capacityNumber; i++) {

            BranchGroup bGroup = new BranchGroup();

            Box box = new Box(raio, raio, raio, criarAppCustom());
            box.setCapability(Box.ENABLE_APPEARANCE_MODIFY);
            Transform3D tfBox = new Transform3D();
            tfBox.setTranslation(new Vector3f(((i * 0.25f) - 0.4f) + 0.01f, 0.0f, -0.25f));
            TransformGroup tgBox = new TransformGroup(tfBox);
            tgBox.addChild(box);

            vectorShadowList.add(new Number(-1, tgBox));


            bGroup.addChild(tgBox);
            su.addBranchGraph(bGroup);


        }

        vectorCapacity = capacityNumber;
        vectorSize = 0;
        vetorNumeros = new Number[vectorCapacity];

        return branchGroup;
    }

    public static BranchGroup listBranchGroup() {

        BranchGroup branchGroup = new BranchGroup();

        Appearance aparencia = addAparencia();

//        String vectorCapacityS = "";
//        int capacityNumber = 0;
//
//        while (capacityNumber == 0 || capacityNumber > 8 || capacityNumber < 2 || vectorCapacityS == null || vectorCapacityS.equals("")) {
//            vectorCapacityS = JOptionPane.showInputDialog("Qual a capacidade da lista? (Mínimo = 2 / Máximo = 8)");
//            if (vectorCapacityS == null || vectorCapacityS.equals("")) {
//            } else {
//                capacityNumber = Integer.parseInt(vectorCapacityS);
//            }
//
//        }

        vectorCapacity = 50;
        vectorSize = 0;
        vetorNumeros = new Number[50];

        return branchGroup;
    }

    public static void main(String[] args) {
        JFrame appFrame = addJanela();
    }

    private static void callAlgorithmHighlight(String algorithm, int phase) {

        if (algorithm.equalsIgnoreCase("bubble")) {

            switch (phase) {

                case 1:
                    highlightsTextWithoutSleep("      auxiliar = v[ j ];\n", textoBubble);
                    break;

                case 2:
                    highlightsTextWithoutSleep("      v[ j ] = v[ j - 1 ];\n", textoBubble);
                    break;

                case 3:
                    highlightsTextWithoutSleep("      v[ j - 1 ] = auxiliar;\n\n", textoBubble);
                    break;

                default:
                    break;

            }

        } else if (algorithm.equalsIgnoreCase("selection")) {

            switch (phase) {

                case 1:
                    highlightsTextWithoutSleep("      aux = v [ index_min ];\n", textoSelection);
                    break;

                case 2:
                    highlightsTextWithoutSleep("      v [ index_min ] = v [ i ];\n", textoSelection);
                    break;

                case 3:
                    highlightsTextWithoutSleep("      v [ i ] = aux;\n\n", textoSelection);
                    break;

                default:
                    break;

            }

        } else if (algorithm.equalsIgnoreCase("insertion")) {

            switch (phase) {

                case 1:
                    highlightsTextWithoutSleep("      auxiliar = v[ j ];\n", textoInsertion);
                    break;

                case 2:
                    highlightsTextWithoutSleep("       v[ j ] = v[ j - 1 ];\n", textoInsertion);
                    break;

                case 3:
                    highlightsTextWithoutSleep("         v[ j - 1 ] = auxiliar;\n", textoInsertion);
                    break;

                default:
                    break;

            }

        } else if (algorithm.equalsIgnoreCase("quick1")) {

            switch (phase) {

                case 1:
                    highlightsTextWithoutSleep("    auxiliar = v [ l ];\n", textoQuick);
                    break;

                case 2:
                    highlightsTextWithoutSleep("    v [ l ] = v [ r ];\n", textoQuick);
                    break;

                case 3:
                    highlightsTextWithoutSleep("    v [ r ] = auxiliar;\n", textoQuick);
                    break;

                default:
                    break;

            }

        } else if (algorithm.equalsIgnoreCase("shell")) {

            switch (phase) {

                case 1:
                    highlightsTextWithoutSleep("          v[ j ] = v [ j - h ];\n", textoShell);
                    break;

                case 2:
                    highlightsTextWithoutSleep("          j = j - h;\n", textoShell);
                    break;

                case 3:
                    highlightsTextWithoutSleep("          j = j - h;\n", textoShell);
                    break;

                default:
                    break;

            }

        } else {

            switch (phase) {

                case 1:
                    highlightsTextWithoutSleep("  auxiliar = v [ l ];\n", textoQuick);
                    break;

                case 2:
                    highlightsTextWithoutSleep("  v [ l ] = v [ fim ];\n", textoQuick);
                    break;

                case 3:
                    highlightsTextWithoutSleep("  v [ fim ] = auxiliar;\n", textoQuick);
                    break;

                default:
                    break;

            }

        }

    }

    private static void moverObjetoGeneric(Number[] v, int n1, int n2, String algorithm) {

        TransformGroup tgElementOne = v[n1].getTGNumber();
        TransformGroup tgElementTwo = v[n2].getTGNumber();

        Transform3D tfElementOne = new Transform3D();
        tgElementOne.getTransform(tfElementOne);
        Vector3f translationElementOne = new Vector3f();
        tfElementOne.get(translationElementOne);

        Transform3D tfElementTwo = new Transform3D();
        tgElementTwo.getTransform(tfElementTwo);
        Vector3f translationElementTwo = new Vector3f();
        tfElementTwo.get(translationElementTwo);


        float xElementOne = translationElementOne.x;
        float yElementOne = translationElementOne.y;
        float xElementOneTemp = xElementOne;

        float xElementTwo = translationElementTwo.x;
        float yElementTwo = translationElementTwo.y;
        float xElementTwoTemp = xElementTwo;

        int i = 0;

        callAlgorithmHighlight(algorithm, 1);

        while (i != 5) {

            yElementOne -= 0.03f;
            yElementTwo += 0.03f;

            translationElementOne.y = yElementOne;
            translationElementTwo.y = yElementTwo;

            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            tfElementTwo.setTranslation(translationElementTwo);
            tgElementTwo.setTransform(tfElementTwo);

            try {
                Thread.sleep(movementSleep * 3);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

            i++;

        }

        callAlgorithmHighlight(algorithm, 2);



        while (true) {

            if (xElementOneTemp >= xElementTwo) {
                break;
            }

            xElementOneTemp += 0.01f;
            xElementTwoTemp -= 0.01f;

            translationElementOne.x = xElementOneTemp;
            translationElementTwo.x = xElementTwoTemp;

            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            tfElementTwo.setTranslation(translationElementTwo);
            tgElementTwo.setTransform(tfElementTwo);

            try {
                Thread.sleep(movementSleep);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

        i = 0;



        callAlgorithmHighlight(algorithm, 3);

        while (i != 5) {

            yElementOne += 0.03f;
            yElementTwo -= 0.03f;

            translationElementOne.y = yElementOne;
            translationElementTwo.y = yElementTwo;

            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            tfElementTwo.setTranslation(translationElementTwo);
            tgElementTwo.setTransform(tfElementTwo);

            try {
                Thread.sleep(movementSleep * 3);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

            i++;

        }

    }

    private static void moverObjetoGenericInverse(Number[] v, int n1, int n2, String algorithm) {

        TransformGroup tgElementOne = v[n1].getTGNumber();
        TransformGroup tgElementTwo = v[n2].getTGNumber();

        Transform3D tfElementOne = new Transform3D();
        tgElementOne.getTransform(tfElementOne);
        Vector3f translationElementOne = new Vector3f();
        tfElementOne.get(translationElementOne);

        Transform3D tfElementTwo = new Transform3D();
        tgElementTwo.getTransform(tfElementTwo);
        Vector3f translationElementTwo = new Vector3f();
        tfElementTwo.get(translationElementTwo);


        float xElementOne = translationElementOne.x;
        float yElementOne = translationElementOne.y;
        float xElementOneTemp = xElementOne;

        float xElementTwo = translationElementTwo.x;
        float yElementTwo = translationElementTwo.y;
        float xElementTwoTemp = xElementTwo;

        int i = 0;

        callAlgorithmHighlight(algorithm, 1);

        while (i != 5) {

            yElementOne -= 0.03f;
            yElementTwo += 0.03f;

            translationElementOne.y = yElementOne;
            translationElementTwo.y = yElementTwo;

            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            tfElementTwo.setTranslation(translationElementTwo);
            tgElementTwo.setTransform(tfElementTwo);

            try {
                Thread.sleep(movementSleep * 3);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

            i++;

        }

        callAlgorithmHighlight(algorithm, 2);



        while (true) {

            if (xElementOneTemp >= xElementTwo) {
                break;
            }

            xElementOneTemp += 0.01f;
            xElementTwoTemp -= 0.01f;

            translationElementOne.x = xElementOneTemp;
            translationElementTwo.x = xElementTwoTemp;

            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            tfElementTwo.setTranslation(translationElementTwo);
            tgElementTwo.setTransform(tfElementTwo);

            try {
                Thread.sleep(movementSleep);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

        i = 0;



        callAlgorithmHighlight(algorithm, 3);

        while (i != 5) {

            yElementOne += 0.03f;
            yElementTwo -= 0.03f;

            translationElementOne.y = yElementOne;
            translationElementTwo.y = yElementTwo;

            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            tfElementTwo.setTranslation(translationElementTwo);
            tgElementTwo.setTransform(tfElementTwo);

            try {
                Thread.sleep(movementSleep * 3);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

            i++;

        }

    }

    public static void removeElements(Number[] v) {

        //Aqui, pega os transformgroups dos ítens à serem trocados.

        for (Number n : v) {
            TransformGroup tgroup = n.getTGNumber();
            Transform3D tform = new Transform3D();
            tgroup.getTransform(tform);

            Vector3f translation = new Vector3f();
            tform.get(translation);

            float x, y;
//            x = translation.z;
            translation.z = 9999999999f;
            tform.setTranslation(translation);
            tgroup.setTransform(tform);

        }

    }

    public static void moveQueueObject(List<Number> list, int index, float x) {

        TransformGroup tgElementOne = list.get(index).getTGNumber();

        Transform3D tfElementOne = new Transform3D();
        tgElementOne.getTransform(tfElementOne);
        Vector3f translationElementOne = new Vector3f();
        tfElementOne.get(translationElementOne);

        float xElementOne = translationElementOne.x;

        while (xElementOne > x) {

            if (xElementOne <= x) {
                break;
            }

            xElementOne -= 0.03f;
            translationElementOne.x = xElementOne;
            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            try {
                Thread.sleep(movementSleep * 2);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

    }

    public static void moveVectorObjectLeft(Number[] v, int index, float x) {

        TransformGroup tgElementOne = v[index].getTGNumber();

        Transform3D tfElementOne = new Transform3D();
        tgElementOne.getTransform(tfElementOne);
        Vector3f translationElementOne = new Vector3f();
        tfElementOne.get(translationElementOne);

        float xElementOne = translationElementOne.x;

        while (xElementOne > x) {

            if (xElementOne <= x) {
                break;
            }

            xElementOne -= 0.03f;
            translationElementOne.x = xElementOne;
            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            try {
                Thread.sleep(movementSleep * 2);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

    }

    public static void moveVectorObjectRight(Number[] v, int index, float x) {

        TransformGroup tgElementOne = v[index].getTGNumber();

        Transform3D tfElementOne = new Transform3D();
        tgElementOne.getTransform(tfElementOne);
        Vector3f translationElementOne = new Vector3f();
        tfElementOne.get(translationElementOne);

        float xElementOne = translationElementOne.x;

        while (xElementOne < x) {

            if (xElementOne >= x) {
                break;
            }

            xElementOne += 0.03f;
            translationElementOne.x = xElementOne;
            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            try {
                Thread.sleep(movementSleep * 2);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

    }
    
    public static void moveVectorObjectUp(Number[] v, int index, float x) {

        TransformGroup tgElementOne = v[index].getTGNumber();

        Transform3D tfElementOne = new Transform3D();
        tgElementOne.getTransform(tfElementOne);
        Vector3f translationElementOne = new Vector3f();
        tfElementOne.get(translationElementOne);

        float yElementOne = translationElementOne.y;

        while (yElementOne < x) {

            if (yElementOne >= x || yElementOne == x - 0.01) {
                break;
            }

            yElementOne += 0.01f;
            translationElementOne.y = yElementOne;
            tfElementOne.setTranslation(translationElementOne);
            tgElementOne.setTransform(tfElementOne);

            try {
                Thread.sleep(30);


            } catch (InterruptedException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

        }

    }

    public void setFrame(JFrame f) {
        Main.frame = f;
    }
}
